package com.stark.commons.spring.core.context;

import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;

import com.stark.commons.spring.core.support.ioc.BeanDefinition;

import lombok.extern.slf4j.Slf4j;

/**
 * 应用上下文工具类，用于从 IOC 容器中获取实例化对象。
 * @author Ben
 * @since 1.0.0
 * @version 1.0.0
 */
@Slf4j
public class ApplicationContextUtil implements ApplicationContextAware {
	
	private static volatile ApplicationContext applicationContext;
	
	@Override
	public void setApplicationContext(@NonNull ApplicationContext applicationContext) {
		ApplicationContextUtil.applicationContext = applicationContext;
	}
	
	/**
	 * 获取应用上下文。
	 * @return 应用上下文对象。
	 */
	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	/**
	 * 获取实例化对象。
	 * @param name 对象名。
	 * @return 实例化对象。
	 * @see org.springframework.beans.factory.BeanFactory#getBean(Class)
	 */
	public static Object getBean(String name) {
		return applicationContext.getBean(name);
	}
	
	/**
	 * 获取实例化对象。
	 * @param requiredType 实例化对象类型。
	 * @return 实例化对象。
	 * @see org.springframework.beans.factory.BeanFactory#getBean(Class)
	 */
	public static <T> T getBean(Class<T> requiredType) {
		return applicationContext.getBean(requiredType);
	}
	
	/**
	 * 获取实例化对象。
	 * @param name 对象名。
	 * @param requiredType 实例化对象类型。
	 * @return 实例化对象。
	 * @see org.springframework.beans.factory.BeanFactory#getBean(String, Class)
	 */
	public static <T> T getBean(String name, Class<T> requiredType) {
		return applicationContext.getBean(name, requiredType);
	}
	
	/**
	 * 动态注册 bean 到 IOC 容器。
	 * @param beanDefinition bean 定义。
	 */
	public static Object registerBean(BeanDefinition beanDefinition) {
		Assert.notNull(applicationContext, "上下文初始化未完成");
		
		GenericBeanDefinition beanDefinitionImpl = new GenericBeanDefinition();
		beanDefinitionImpl.setBeanClassName(beanDefinition.getBeanClassName());
		beanDefinitionImpl.setPropertyValues(new MutablePropertyValues(beanDefinition.getProperties()));
		beanDefinitionImpl.setAbstract(beanDefinition.isAbstract());
		beanDefinitionImpl.setAutowireCandidate(beanDefinition.isAutowireCandidate());
		beanDefinitionImpl.setAutowireMode(beanDefinition.getAutowireMode());
		beanDefinitionImpl.setDependencyCheck(beanDefinition.getDependencyCheck());
		beanDefinitionImpl.setDependsOn(beanDefinition.getDependsOn());
		beanDefinitionImpl.setDestroyMethodName(beanDefinition.getDestroyMethodName());
		beanDefinitionImpl.setInitMethodName(beanDefinition.getInitMethodName());
		beanDefinitionImpl.setLazyInit(beanDefinition.isLazyInit());
		beanDefinitionImpl.setParentName(beanDefinition.getParentName());
		beanDefinitionImpl.setPrimary(beanDefinition.isPrimary());
		beanDefinitionImpl.setRole(beanDefinition.getRole());
		beanDefinitionImpl.setScope(beanDefinition.getScope());
        
		ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;
        BeanDefinitionRegistry beanDefinitonRegistry = (BeanDefinitionRegistry) configurableApplicationContext.getBeanFactory();
        beanDefinitonRegistry.registerBeanDefinition(beanDefinition.getBeanName(), beanDefinitionImpl);
        
        log.info("动态注入 bean 到 IOC 容器: beanClassName={},beanName={}",
        		beanDefinition.getBeanClassName(), beanDefinition.getBeanName());
        
        return getBean(beanDefinition.getBeanName());
	}
	
}